#pragma once
#include <cstdint>
#include <string>
#include <iostream>

constexpr static auto time_from_string(const char* str, int offset) {
	return static_cast<uint32_t>(str[offset] - '0') * 10 +
		static_cast<uint32_t>(str[offset + 1] - '0');
}

constexpr static auto get_num(const char str) {
	return static_cast<uint32_t>(str - '0');
}

constexpr static auto get_seed_constexpr() {
	auto time = __TIME__;
	auto date = __DATE__;
	return time_from_string(time, 0) * 60 * 60 + get_num(date[4]) + get_num(date[5])
		+ get_num(date[7]) + get_num(date[8]) + get_num(date[9]) + get_num(date[10]);
}

constexpr uint8_t keyStroker = get_seed_constexpr() % 0xffui8 /*MAX UINT8*/;

namespace StringEncoder
{

	template<typename T >
	constexpr T encodeChar(const T character, size_t index) {
		return static_cast<T>(character ^ (static_cast<T>(keyStroker) + index));
	}

	template <size_t size, typename T>
	class XorStringEncoder {
	public:
		const size_t strLength = size - 1;
		T encryptetString[size];

		constexpr XorStringEncoder(const T* string) : encryptetString{} {
			for (size_t i = 0u; i < size; ++i)
				encryptetString[i] = encodeChar<T>(string[i], i);
		}

		const T* decodeString() const {
			T* decryptedString = const_cast<T*>(encryptetString);

			for (size_t i = 0; i < strLength; ++i)
				decryptedString[i] = static_cast<T>(decryptedString[i] ^ (static_cast<T>(keyStroker) + i));

			decryptedString[strLength] = '\0';
			return decryptedString;
		}

	};
};

#define _c( string_in )  (char*)    ([]()->auto { constexpr StringEncoder::XorStringEncoder<(sizeof(string_in)/sizeof(char)), char> ex(string_in); return ex; }().decodeString())
#define _cw( string_in ) (wchar_t*) ([]()->auto { constexpr StringEncoder::XorStringEncoder<(sizeof(string_in)/sizeof(wchar_t)), wchar_t> ex(string_in); return ex; }().decodeString())